﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Xml.Linq;
using CAION2.Models;
using CAION2.Properties;
using CAION2.Helpers;
using CAION2.ViewModels;

namespace CAION2.Classes
{
    public class CharacterStats
    {
        #region Vars

        private DataTable statsTable;
        private string selectedGameClass;
        private byte currentCharacterLevel;
        private readonly List<bool> itemsCorrect;

        private XDocument xSkillLearns;
        private XDocument xSkills;
        private List<XElement> classPassiveSkills;
        private readonly Dictionary<string, byte> physicalDefendKoeffs; 

        #endregion
        
        #region Properties

        public DataTable StatsTable
        {
            get { return statsTable; }
            private set
            {
                if (Equals(statsTable, value)) return;
                statsTable = value;
            }
        }

        public bool FreezeCalculate { private get; set; }

        #endregion

        public CharacterStats()
        {
            Mediator.Instance.Register(o => GetCardIsCorrect((KeyValuePair<byte, bool>)o), Messages.CardCorrectCheck);
            Mediator.Instance.Register(o => FillStatFromCard((KeyValuePair<byte, ItemCardViewModel.StatsValuesClass>)o), Messages.CardStatsSend);
            Mediator.Instance.Register(o => NulledStatsFromCard((byte)o), Messages.CardStatsNullSend);
            
            itemsCorrect = new List<bool>{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true };
            physicalDefendKoeffs = new Dictionary<string, byte>
                {
                    {"place6", 3},      //torso
                    {"place7", 2},         //leg
                    {"place9", 1},        //foot
                    {"place13", 1},       //glove
                    {"place12", 1}     //shoulder
                };

            FreezeCalculate = false;

            #region Create Stats table

            StatsTable = new DataTable("Stats");
            StatsTable.Columns.Add("Position", typeof (Byte));
            StatsTable.Columns.Add("Name", typeof (String));
            StatsTable.Columns.Add("Translate", typeof (String));
            StatsTable.Columns.Add("IsProcent", typeof (bool));
            StatsTable.Columns.Add("ClassValue", typeof (Single));
            StatsTable.Columns.Add("PassiveValue", typeof (Single));
            StatsTable.Columns.Add("PassiveAttackOffensive", typeof (Single));

            StatsTable.Columns.Add("Place1", typeof (Single));
            StatsTable.Columns.Add("Place2", typeof (Single));
            StatsTable.Columns.Add("Place3", typeof (Single));
            StatsTable.Columns.Add("Place4", typeof (Single));
            StatsTable.Columns.Add("Place5", typeof (Single));
            StatsTable.Columns.Add("Place6", typeof (Single));
            StatsTable.Columns.Add("Place7", typeof (Single));
            StatsTable.Columns.Add("Place8", typeof (Single));
            StatsTable.Columns.Add("Place9", typeof (Single));
            StatsTable.Columns.Add("Place10", typeof (Single));
            StatsTable.Columns.Add("Place11", typeof (Single));
            StatsTable.Columns.Add("Place12", typeof (Single));
            StatsTable.Columns.Add("Place13", typeof (Single));
            StatsTable.Columns.Add("Place14", typeof (Single));
            StatsTable.Columns.Add("Place15", typeof (Single));
            
            StatsTable.Columns.Add("Place1_bonus", typeof(Single));
            StatsTable.Columns.Add("Place2_bonus", typeof(Single));
            StatsTable.Columns.Add("Place3_bonus", typeof(Single));
            StatsTable.Columns.Add("Place4_bonus", typeof(Single));
            StatsTable.Columns.Add("Place5_bonus", typeof(Single));
            StatsTable.Columns.Add("Place6_bonus", typeof(Single));
            StatsTable.Columns.Add("Place7_bonus", typeof(Single));
            StatsTable.Columns.Add("Place8_bonus", typeof(Single));
            StatsTable.Columns.Add("Place9_bonus", typeof(Single));
            StatsTable.Columns.Add("Place10_bonus", typeof(Single));
            StatsTable.Columns.Add("Place11_bonus", typeof(Single));
            StatsTable.Columns.Add("Place12_bonus", typeof(Single));
            StatsTable.Columns.Add("Place13_bonus", typeof(Single));
            StatsTable.Columns.Add("Place14_bonus", typeof(Single));
            StatsTable.Columns.Add("Place15_bonus", typeof(Single));
            StatsTable.Columns.Add("ItemSet", typeof(Single));
            
            StatsTable.Columns.Add("BasicSum", typeof (Single));
            StatsTable.Columns.Add("BonusSum", typeof (Single));
            StatsTable.Columns.Add("Sums", typeof (Single));
            StatsTable.Columns.Add("Procent", typeof (Single));

            StatsTable.Columns.Add("BasicSumText", typeof (string));
            StatsTable.Columns.Add("BonusSumText", typeof (string));
            StatsTable.Columns.Add("SumsText", typeof (string));

            StatsTable.Columns.Add("Tips", typeof(string));
            
            StatsTable.Columns["Place1"].DefaultValue = 0;
            StatsTable.Columns["Place2"].DefaultValue = 0;
            StatsTable.Columns["Place3"].DefaultValue = 0;
            StatsTable.Columns["Place4"].DefaultValue = 0;
            StatsTable.Columns["Place5"].DefaultValue = 0;
            StatsTable.Columns["Place6"].DefaultValue = 0;
            StatsTable.Columns["Place7"].DefaultValue = 0;
            StatsTable.Columns["Place8"].DefaultValue = 0;
            StatsTable.Columns["Place9"].DefaultValue = 0;
            StatsTable.Columns["Place10"].DefaultValue = 0;
            StatsTable.Columns["Place11"].DefaultValue = 0;
            StatsTable.Columns["Place12"].DefaultValue = 0;
            StatsTable.Columns["Place13"].DefaultValue = 0;
            StatsTable.Columns["Place14"].DefaultValue = 0;
            StatsTable.Columns["Place15"].DefaultValue = 0;

            StatsTable.Columns["Place1_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place2_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place3_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place4_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place5_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place6_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place7_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place8_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place9_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place10_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place11_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place12_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place13_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place14_bonus"].DefaultValue = 0;
            StatsTable.Columns["Place15_bonus"].DefaultValue = 0;
            StatsTable.Columns["ItemSet"].DefaultValue = 0;
            
            StatsTable.Columns["IsProcent"].DefaultValue = false;
            StatsTable.Columns["ClassValue"].DefaultValue = 0;
            StatsTable.Columns["PassiveValue"].DefaultValue = 0;
            StatsTable.Columns["PassiveAttackOffensive"].DefaultValue = 0;
            StatsTable.Columns["BasicSum"].DefaultValue = 0;
            StatsTable.Columns["BonusSum"].DefaultValue = 0;
            StatsTable.Columns["Sums"].DefaultValue = 0;
            StatsTable.Columns["Procent"].DefaultValue = 0;
            
            DataColumn[] primaryColumns = new DataColumn[2];
            primaryColumns[0] = StatsTable.Columns["Position"];
            primaryColumns[1] = StatsTable.Columns["Name"];
            StatsTable.PrimaryKey = primaryColumns;
            
            #endregion
        }

        public void FillCharacterStats(string gameClass, byte characterLevel)
        {
            foreach (DataRow nullrow in StatsTable.Rows)
            {
                nullrow["ClassValue"] = 0;
                nullrow["PassiveValue"] = 0;
                nullrow["PassiveAttackOffensive"] = 0;
            }

            selectedGameClass = gameClass;
            currentCharacterLevel = characterLevel;

            DataRow row = AddSelectStatToTable("maxhp");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("maxhp", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("maxmp");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("maxmp", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("phyattack");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("phyattack", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("hitaccuracy");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("hitaccuracy", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("critical");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("critical", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("phyattack_l");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("phyattack_l", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("hitaccuracy_l");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("hitaccuracy_l", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("critical_l");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("critical_l", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("attackdelay");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("attackdelay", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("boostcastingtime");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("boostcastingtime", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("speed");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("speed", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("flyspeed");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("flyspeed", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("magicalhitaccuracy");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("magicalhitaccuracy", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("magicalcritical");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("magicalcritical", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("magicalcriticalreducerate");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("magicalcriticalreducerate", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("maxfp");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("maxfp", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("dodge");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("dodge", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("parry");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("parry", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("block");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("block", selectedGameClass, currentCharacterLevel);

            row = AddSelectStatToTable("physicalcriticalreducerate");
            row["ClassValue"] = ClassGameClass.GetClassStatValue("physicalcriticalreducerate", selectedGameClass, currentCharacterLevel);
           
            StatsTable.AcceptChanges();
        }

        private DataRow AddSelectStatToTable(string statName)
        {
            DataRow row = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), statName));

            if (row == null)
            {
                row = StatsTable.NewRow();
                row["Position"] = GetStatPosition(statName);
                row["Name"] = statName;
                row["Translate"] = CardStat.GetStatTranslate(statName);
                row["IsProcent"] = GetStatIsProcent(statName);
                StatsTable.Rows.Add(row);
            }

            return row;
        }

        private static byte GetStatPosition(string statName)
        {
            List<string> positions = new List<string>
                {
                    "maxhp", 
                    "maxmp", 
                    "pvpattackratiophysical", 
                    "pvpattackratio",
                    "phyattack",
                    "hitaccuracy",
                    "critical",
                    "phyattack_l",
                    "hitaccuracy_l",
                    "critical_l",
                    "attackdelay",
                    "boostcastingtime",
                    "speed",
                    "flyspeed",
                    "magicalskillboost",
                    "magicalhitaccuracy",
                    "magicalcritical",
                    "magicalresist",
                    "concentration",
                    "magicalskillboostresist",
                    "magicalcriticalreducerate",
                    "maxfp",
                    "dodge",
                    "parry",
                    "block",
                    "physicalcriticalreducerate",
                    "pvpdefendratio",
                    "boosthate",
                    "elementaldefendair",
                    "elementaldefendearth",
                    "elementaldefendfire",
                    "elementaldefendwater",
                    "stumble_arp",
                    "arstagger",
                };

            byte position = (byte)(positions.FindIndex(p => p == statName.ToLower()) + 1);
            if (position == 0) position = 99;

            return position;
        }
        
        private static bool GetStatIsProcent(string statName)
        {
            switch (statName.ToLower())
            {
                case "pvpdefendratio":
                case "pvpattackratio":
                case "pvpattackratiophysical":
                case "boosthate":
                    return true;

                default:
                    return false;
            }
        }

        public void CalculateStats(string statName = "")
        {
            if (FreezeCalculate) return;
            
            foreach (DataRow row in StatsTable.Rows.Cast<DataRow>().Where(row => string.IsNullOrEmpty(statName) || row["Name"].ToString() == statName))
            {
                switch (row["Name"].ToString())
                {
                    case "phyattack":
                        CalculatePhyAttackStats();
                        break;
                    case "critical":
                    case "hitaccuracy":
                        CalculateHandsOtherStats(row["Name"].ToString());
                        break;
                    case "phyattack_l":
                    case "critical_l":
                        break;
                    case "attackdelay":
                        CalculateAttackDelayStat(row);
                        break;
                    case "speed":
                    case "flyspeed":
                        CalculateSpeedStat(row);
                        break;
                    case "boostcastingtime":
                        CalculateSpeedStat(row, true);
                        break;
                    case "physicaldefend":
                        CalculatePhysicalDefendStat(row);
                        break;
                    default:
                        CalculateStat(row);
                        break;
                }

                CalculateProcentAndBigSum(row);
                UpdateStatsSumsText(row);
            }

            StatsTable.AcceptChanges();
        }

        private Single PlacesSum(DataRow row, bool isBonus)
        {
            byte skipIndex = !isBonus ? (byte)7 : (byte)22;
            byte takeIndex = !isBonus ? (byte)15 : (byte)16;
            List<Single> places = row.ItemArray.Skip(skipIndex).Take(takeIndex).OfType<Single>().ToList();

            return places.Where((t, i) => itemsCorrect[i]).Sum();
        }

        #region Calculating some stats

        private void CalculateStat(DataRow row)
        {
            row["BasicSum"] = Convert.ToSingle(row["ClassValue"]) + PlacesSum(row, false);
            row["BonusSum"] = Convert.ToSingle(row["PassiveValue"]) + PlacesSum(row, true);
        }

        private void CalculateAttackDelayStat(DataRow row)
        {
            if ((Single) row["place1"] > 0 && itemsCorrect[0])
            {
                row["BasicSum"] = Convert.ToSingle(row["place1"]);
            }
            else
            {
                row["BasicSum"] = Convert.ToSingle(row["ClassValue"]);
            }
            
            row["BonusSum"] = Math.Round(((Single)row["BasicSum"] * PlacesSum(row, true) * -0.01), 1);
        }

        private void CalculatePhyAttackStats()
        {
            DataRow a1 = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), "phyattack"));
            DataRow a2 = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), "phyattack_l"));

            if (a1 == null || a2 == null) return;
            
            if ((Single)a1["place1"] > 0 && itemsCorrect[0])
            {
                a1["BasicSum"] = Math.Floor(Convert.ToSingle(a1["place1"]) * ClassGameClass.GetPower(selectedGameClass) * 0.01);

                CalculatePassiveSkillsForWeapon(a1["tips"].ToString(), "phyattack");
                
                a1["BonusSum"] = PlacesSum(a1, true) 
                                    + Convert.ToSingle(a1["PassiveValue"])
                                    + Convert.ToSingle(a1["PassiveAttackOffensive"])
                                    + Convert.ToSingle(a1["PassiveValue"]);
            }
            else
            {
                a1["BasicSum"] = Convert.ToSingle(a1["ClassValue"]);
                a1["BonusSum"] = Convert.ToSingle(a1["PassiveValue"]);
            }

            if ((Single)a2["place2"] > 0 && itemsCorrect[1])
            {
                a2["BasicSum"] = Math.Floor(Convert.ToSingle(a2["place2"]) * ClassGameClass.GetPower(selectedGameClass) * 0.01);

                CalculatePassiveSkillsForWeapon(a2["tips"].ToString(), "phyattack_l");

                a2["BonusSum"] = PlacesSum(a2, true)
                                    + Convert.ToSingle(a2["PassiveValue"])
                                    + Convert.ToSingle(a2["PassiveAttackOffensive"]);
            }
            else
            {
                a2["BasicSum"] = 0;
                a2["BonusSum"] = 0;
            }
            
            CalculateProcentAndBigSum(a1);
            UpdateStatsSumsText(a1);
            CalculateProcentAndBigSum(a2);
            UpdateStatsSumsText(a2);
        }

        private void CalculateHandsOtherStats(string statName)
        {
            DataRow c1 = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), statName));
            DataRow c2 = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), statName + "_l"));

            if (c1 == null || c2 == null) return;
            
            c1["BasicSum"] = Convert.ToSingle(c1["ClassValue"]) + PlacesSum(c1, false);
            c1["BonusSum"] = Convert.ToSingle(c1["PassiveValue"]) + PlacesSum(c1, true);
            
            if ((Single)c2["place2"] > 0 && itemsCorrect[1])
            {
                c2["BasicSum"] = Convert.ToSingle(c2["ClassValue"]) + PlacesSum(c2, false);
                c2["BonusSum"] = Convert.ToSingle(c2["PassiveValue"]) + PlacesSum(c2, true);
            }
            else
            {
                c2["BasicSum"] = 0;
                c2["BonusSum"] = 0;
            }

            CalculateProcentAndBigSum(c1);
            UpdateStatsSumsText(c1);
            CalculateProcentAndBigSum(c2);
            UpdateStatsSumsText(c2);
        }

        private void CalculateSpeedStat(DataRow row, bool isNegative = false)
        {
            Single koef = 0.01f;
            if (isNegative) koef = -0.01f;
            row["BasicSum"] = Convert.ToSingle(row["ClassValue"]) + PlacesSum(row, false);
            row["BonusSum"] = Math.Round(((Single)row["BasicSum"] * PlacesSum(row, true) * koef), 1);
        }

        private void CalculatePhysicalDefendStat(DataRow row)
        {
            row["BasicSum"] = Convert.ToSingle(row["ClassValue"]) + PlacesSum(row, false);
            row["BonusSum"] = Convert.ToSingle(row["PassiveValue"]) + PlacesSum(row, true);

            Byte itemsCount = 0;
            Byte fullIndex = 0;
            for (int i = 1; i < 16; i++)
            {
                if (!((Single) row["place" + i] > 0)) continue;

                itemsCount = (byte)(itemsCount + 1);
                if (physicalDefendKoeffs.ContainsKey("place" + i))
                    fullIndex = (byte) (fullIndex + physicalDefendKoeffs["place" + i]);
            }

            switch (itemsCount)
            {
                case 1:
                    break;
                case 2:
                    if (fullIndex < 4) fullIndex = (Byte)(fullIndex + 1);
                    break;
                case 3:
                case 4:
                    fullIndex = (Byte)(fullIndex + 1);
                    break;
                case 5:
                    fullIndex = (Byte)(fullIndex + 2);
                    break;
            }

            Single resultBonus = (Single)((((Single)row["BasicSum"] * 0.1) + 10) * 0.1);
            resultBonus = (Single) Math.Floor(resultBonus*fullIndex);
            row["BonusSum"] = (Single)row["BonusSum"] + resultBonus;
        }

        #endregion

        private static void CalculateProcentAndBigSum(DataRow row)
        {
            if ((Single)row["BasicSum"] > 0)
            {
                row["Procent"] = Math.Round((Single)row["BonusSum"] * 100 / (Single)row["BasicSum"], 1);
            }
            else
            {
                if ((Single) row["BonusSum"] > 0)
                {
                    row["Procent"] = 100;
                }
                else
                {
                    row["Procent"] = 0;
                }
            }

            row["Sums"] = Convert.ToSingle(row["BasicSum"]) + Convert.ToSingle(row["BonusSum"]);
        }

        private static void UpdateStatsSumsText(DataRow row)
        {
            string pSign = "";
            if ((bool) row["IsProcent"]) pSign = "%";

            row["BasicSumText"] = string.Format("{0}{1}", row["BasicSum"], pSign);
            row["SumsText"] = string.Format("{0}{1}", row["Sums"], pSign);
            if ((Single)row["BonusSum"] > 0)
            {
                row["BonusSumText"] = string.Format("+{0}{1}", row["BonusSum"], pSign);
            }
            else
            {
                row["BonusSumText"] = string.Format("{0}{1}", row["BonusSum"], pSign);
            }
        }

        private void GetCardIsCorrect(KeyValuePair<byte, bool> cardInfo)
        {
            itemsCorrect[cardInfo.Key - 1] = cardInfo.Value;

            if (itemsCorrect.Take(15).Any(i => i == false))
            {
                itemsCorrect[15] = false;
            }
            else
            {
                itemsCorrect[15] = true;
            }
        }

        private void FillStatFromCard(KeyValuePair<byte, ItemCardViewModel.StatsValuesClass> stat)
        {
            DataRow row = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), stat.Value.Stat)) 
                          ?? AddSelectStatToTable(stat.Value.Stat);

            switch (stat.Value.Stat)
            {
                case "phyattack":
                    FillPhyAttackStatFromCard(stat, row);
                    break;
                case "critical":
                case "hitaccuracy":
                    FillHandsOtherStatFromCard(stat, row);
                    break;
                default:
                    row["place" + stat.Key] = stat.Value.BasicValue;
                    row["place" + stat.Key + "_bonus"] = stat.Value.BonusValue 
                                                            + stat.Value.EnchantValue
                                                            + stat.Value.IdianValue
                                                            + stat.Value.RandomBonusValue
                                                            + stat.Value.GodEnchantValue
                                                            + stat.Value.ArmsfusionBonusValue
                                                            + stat.Value.ArmsfusionManaStoneValue
                                                            + stat.Value.ManaStoneValue;
                    if (!string.IsNullOrEmpty(stat.Value.Tips)) row["tips"] = stat.Value.Tips;
                    break;
            }

            StatsTable.AcceptChanges();
            CalculateStats(stat.Value.Stat);
        }

        private void FillPhyAttackStatFromCard(KeyValuePair<byte, ItemCardViewModel.StatsValuesClass> stat, DataRow row)
        {
            DataRow lRow = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), stat.Value.Stat + "_l"))
                          ?? AddSelectStatToTable(stat.Value.Stat);

            switch (stat.Key)
            {
                case 1:
                    row["place" + stat.Key] = (stat.Value.BasicValue + stat.Value.BasicValue2) / 2 + stat.Value.EnchantValue;
                    row["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                        + stat.Value.IdianValue
                                                        + stat.Value.RandomBonusValue
                                                        + stat.Value.GodEnchantValue
                                                        + stat.Value.ArmsfusionBonusValue
                                                        + stat.Value.ArmsfusionManaStoneValue
                                                        + stat.Value.ManaStoneValue;
                    lRow["place1_bonus"] = stat.Value.ManaStoneValue;
                    if (!string.IsNullOrEmpty(stat.Value.Tips)) row["tips"] = stat.Value.Tips;
                    break;
                case 2:
                    lRow["place" + stat.Key] = (stat.Value.BasicValue + stat.Value.BasicValue2) / 2 + stat.Value.EnchantValue;
                    lRow["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                        + stat.Value.IdianValue
                                                        + stat.Value.RandomBonusValue
                                                        + stat.Value.GodEnchantValue
                                                        + stat.Value.ArmsfusionBonusValue
                                                        + stat.Value.ArmsfusionManaStoneValue
                                                        + stat.Value.ManaStoneValue;
                    row["place2_bonus"] = stat.Value.ManaStoneValue;
                    if (!string.IsNullOrEmpty(stat.Value.Tips)) lRow["tips"] = stat.Value.Tips;
                    break;
                default:
                    row["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                            + stat.Value.EnchantValue
                                                            + stat.Value.IdianValue
                                                            + stat.Value.RandomBonusValue
                                                            + stat.Value.GodEnchantValue
                                                            + stat.Value.ArmsfusionBonusValue
                                                            + stat.Value.ArmsfusionManaStoneValue
                                                            + stat.Value.ManaStoneValue;
                    lRow["place" + stat.Key + "_bonus"] = row["place" + stat.Key + "_bonus"];
                    break;
            }
        }

        private void FillHandsOtherStatFromCard(KeyValuePair<byte, ItemCardViewModel.StatsValuesClass> stat, DataRow row)
        {
            DataRow lRow = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), stat.Value.Stat + "_l"))
                          ?? AddSelectStatToTable(stat.Value.Stat);

            switch (stat.Key)
            {
                case 1:
                    row["place" + stat.Key] = stat.Value.BasicValue;
                    row["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                        + stat.Value.IdianValue
                                                        + stat.Value.RandomBonusValue
                                                        + stat.Value.GodEnchantValue
                                                        + stat.Value.ArmsfusionBonusValue
                                                        + stat.Value.ArmsfusionManaStoneValue
                                                        + stat.Value.ManaStoneValue;
                    lRow["place1_bonus"] = stat.Value.ManaStoneValue;
                    if (!string.IsNullOrEmpty(stat.Value.Tips)) row["tips"] = stat.Value.Tips;
                    break;
                case 2:
                    lRow["place" + stat.Key] = stat.Value.BasicValue;
                    lRow["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                        + stat.Value.IdianValue
                                                        + stat.Value.RandomBonusValue
                                                        + stat.Value.GodEnchantValue
                                                        + stat.Value.ArmsfusionBonusValue
                                                        + stat.Value.ArmsfusionManaStoneValue
                                                        + stat.Value.ManaStoneValue;
                    row["place2_bonus"] = stat.Value.ManaStoneValue;
                    if (!string.IsNullOrEmpty(stat.Value.Tips)) lRow["tips"] = stat.Value.Tips;
                    break;
                default:
                    row["place" + stat.Key] = stat.Value.BasicValue;
                    lRow["place" + stat.Key] = row["place" + stat.Key];
                    row["place" + stat.Key + "_bonus"] = stat.Value.BonusValue
                                                            + stat.Value.EnchantValue
                                                            + stat.Value.IdianValue
                                                            + stat.Value.RandomBonusValue
                                                            + stat.Value.GodEnchantValue
                                                            + stat.Value.ArmsfusionBonusValue
                                                            + stat.Value.ArmsfusionManaStoneValue
                                                            + stat.Value.ManaStoneValue;
                    lRow["place" + stat.Key + "_bonus"] = row["place" + stat.Key + "_bonus"];
                    break;
            }
        }

        private void NulledStatsFromCard(byte placeIndex)
        {
            foreach (DataRow row in StatsTable.Rows)
            {
                row["place" + placeIndex] = 0;
                row["place" + placeIndex + "_bonus"] = 0;
                if (placeIndex == 1) row["PassiveAttackOffensive"] = 0;
            }

            itemsCorrect[placeIndex - 1] = true;

            StatsTable.AcceptChanges();
            CalculateStats();
        }

        public void ClearStatsFromItemSets()
        {
            foreach (DataRow row in StatsTable.Rows)
            {
                row["ItemSet"] = 0;
            }

            StatsTable.AcceptChanges();
        }

        public void FillStatsFromItemSet(IEnumerable<KeyValuePair<string, float>> itemSetStats)
        {
            foreach (KeyValuePair<string, float> setStat in itemSetStats)
            {
                DataRow row = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), setStat.Key))
                          ?? AddSelectStatToTable(setStat.Key);

                row["ItemSet"] = (float)row["ItemSet"] + setStat.Value;
                if (setStat.Key == "phyattack" || setStat.Key == "critical" || setStat.Key == "hitaccuracy")
                {
                    DataRow lRow = StatsTable.Rows.Cast<DataRow>().SingleOrDefault(statRow => Equals(statRow["Name"].ToString(), setStat.Key+"_l"))
                          ?? AddSelectStatToTable(setStat.Key);
                    lRow["ItemSet"] = row["ItemSet"];
                }
            }

            StatsTable.AcceptChanges();
        }

        #region Passive Skills

        public void LoadPassiveSkills()
        {
            if (xSkillLearns == null)
                xSkillLearns = XDocument.Load(DataModel.WorkDirectory + "\\Data\\client_skill_learns_passive.xml");
            if (xSkills == null)
                xSkills = XDocument.Load(DataModel.WorkDirectory + "\\Data\\client_skills_passive.xml");

            XElement skillLearnsRoot = xSkillLearns.Element("client_skill_learns");
            if (skillLearnsRoot == null) return;

            string[] classNames = SetGameClassNameForPassiveSkills();

            List<String> skillLearns =
                (skillLearnsRoot.Descendants("client_skill_learn")
                                .AsParallel()
                                .Select(sk => new {sk, skill = sk.Element("class")})
                                .
                                 Where(@t =>
                                     {
                                         XElement pcLevel = @t.sk.Element("pc_level");
                                         return pcLevel != null &&
                                                (@t.skill != null && ((@t.skill.Value == classNames[0] ||
                                                                       @t.skill.Value == classNames[1]) &&
                                                                      (Convert.ToByte(pcLevel.Value) <=
                                                                       currentCharacterLevel)));
                                     })
                                .Select(@t =>
                                    {
                                        XElement skillOut = @t.sk.Element("skill");
                                        return skillOut != null ? skillOut.Value : null;
                                    })).ToList();

            skillLearns = skillLearns.Distinct().ToList();
            skillLearns.Sort();
            skillLearns.Reverse();

            List<String> skillLearnsShot = new List<string>();
            String compareText = "";

            foreach (string s in skillLearns)
            {
                String subs = s.Substring(0, s.Length - 1);
                if (subs == compareText) continue;
                compareText = subs;
                skillLearnsShot.Add(s);
            }

            XElement xElement = xSkills.Element("skill_base_clients");

            if (xElement == null) return;

            classPassiveSkills =
                (from sk in xElement.Descendants("skill_base_client").AsParallel()
                 let element = sk.Element("name")
                 where element != null && skillLearnsShot.Contains(element.Value)
                 select sk).ToList();

            CalculatePassiveSkillsForPC();
        }

        private string[] SetGameClassNameForPassiveSkills()
        {
            string[] values = {"", ""};

            if (selectedGameClass == Resources.Class_Fighter) return new[] {"FIGHTER", "WARRIOR"};
            if (selectedGameClass == Resources.Class_Knight) return new[] {"KNIGHT", "WARRIOR"};

            if (selectedGameClass == Resources.Class_Ranger) return new[] {"RANGER", "SCOUT"};
            if (selectedGameClass == Resources.Class_Assassin) return new[] {"ASSASSIN", "SCOUT"};

            if (selectedGameClass == Resources.Class_Priest) return new[] {"PRIEST", "CLERIC"};
            if (selectedGameClass == Resources.Class_Chanter) return new[] {"CHANTER", "CLERIC"};

            if (selectedGameClass == Resources.Class_Wizard) return new[] {"WIZARD", "MAGE"};
            if (selectedGameClass == Resources.Class_Elementalist) return new[] {"ELEMENTALLIST", "MAGE"};

            if (selectedGameClass == Resources.Class_Gunner) return new[] { "RIDER", "ENGINEER" };
            if (selectedGameClass == Resources.Class_Gunner) return new[] {"GUNNER", "ENGINEER"};

            if (selectedGameClass == Resources.Class_Bard) return new[] {"BARD", "ARTIST"};

            return values;
        }

        //TODO: Сделать окно с выбором пассивок которые были изучены + тех что специфичиские типа в полете
        private void CalculatePassiveSkillsForPC()
        {
            List<XElement> localPassiveSkills = (from skill in classPassiveSkills.AsParallel()
                                                 let xtype = skill.Element("effect1_type")
                                                 let xname = skill.Element("name")
                                                 where xtype != null && (xtype.Value == "StatBoost" || xtype.Value == "BoostHate")
                                                                     && xname.Value.StartsWith("P_")
                                                 select skill).OrderBy(x =>
                                                 {
                                                     XElement xName2 = x.Element("name");
                                                     return xName2 != null ? xName2.Value : null;
                                                 }).ToList();
            
            foreach (XElement passiveSkill in localPassiveSkills)
            {
                Single pasiveValue;
                Single procentValue;
                byte skillLevel;

                ConvertPassiveSkill(passiveSkill, 1, out pasiveValue, out procentValue, out skillLevel);

                XElement skillCode = passiveSkill.Element("effect1_reserved13");
                if (skillCode == null)
                {
                    XElement xE1Type = passiveSkill.Element("effect1_type");
                    if (xE1Type != null && xE1Type.Value != "StatBoost")
                    {
                        skillCode = passiveSkill.Element("effect1_type");
                        if (skillCode == null) continue;
                    }
                    else
                    {
                        continue;
                    }
                }

                DataRow row;

                switch (skillCode.Value.ToLower())
                {
                    //case "phyattack":
                    //    row = AddSelectStatToTable(skillCode.Value.ToLower());
                    //    if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                    //    break;
                    case "elementaldefendall":
                        row = AddSelectStatToTable("elementaldefendair");
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                        row = AddSelectStatToTable("elementaldefendearth");
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                        row = AddSelectStatToTable("elementaldefendfire");
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                        row = AddSelectStatToTable("elementaldefendwater");
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                        break;
                    case "boosthate":
                    case "pvpdefendratio":
                    case "pvpattackratio":
                    case "pvpattackratiophysical":
                        row = AddSelectStatToTable(skillCode.Value.ToLower());
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue * 0.1;
                        break;
                    default:
                        row = AddSelectStatToTable(skillCode.Value.ToLower());
                        if (Math.Abs(pasiveValue - 0) > 0) row["PassiveValue"] = (Single)row["PassiveValue"] + pasiveValue;
                        if (Math.Abs(procentValue - 0) > 0)
                        {
                            CalculateStats(skillCode.Value.ToLower());
                            row["PassiveValue"] = (Single)row["PassiveValue"] + (float)Math.Floor((Single)row["BasicSum"] * procentValue * 0.01);
                        }
                        break;
                }
            }
        }

        private void CalculatePassiveSkillsForWeapon(string weaponType, string handAttack)
        {
            DataRow row = AddSelectStatToTable(handAttack);

            if (Math.Abs((Single)row["place1"] + (Single)row["place2"] - 0) <= 0) return;

            List<XElement> localPassiveSkills = (from skill in classPassiveSkills.AsParallel()
                                                 let xtype = skill.Element("effect1_type")
                                                 let xname = skill.Element("name")
                                                 let xwpn = skill.Element("effect1_reserved5")
                                                 where xtype != null && (xwpn != null && (xwpn.Value.ToLower() == weaponType
                                                                                                    && xtype.Value == "Wpn_Mastery"
                                                                                                    && xname.Value.StartsWith("P_")))
                                                 select skill).OrderBy(x =>
                                                     {
                                                         XElement element = x.Element("effect1_basiclv");
                                                         return element != null ? element.Value : null;
                                                     }).ToList();
            
            if (localPassiveSkills.Count == 0)
            {
                row["PassiveAttackOffensive"] = 0;
                return;
            }

            XElement localPassiveSkill = localPassiveSkills.Last();

            Single pasiveValue;
            Single procentValue;
            byte skillLevel;
            
            ConvertPassiveSkill(localPassiveSkill, 1, out procentValue, out pasiveValue, out skillLevel);

            if (pasiveValue > 0) row["PassiveAttackOffensive"] = pasiveValue;
            if (procentValue > 0)
                row["PassiveAttackOffensive"] = Math.Floor((Single) row["BasicSum"]*procentValue*0.01);
        }

        private void ConvertPassiveSkill(XElement passiveSkill, byte effectNumber, out Single pasiveValue,
                                         out Single procentValue, out byte skillLevel)
        {
            pasiveValue = 0;
            procentValue = 0;
            skillLevel = 0;

            XElement attribute2 = passiveSkill.Element("effect" + effectNumber + "_reserved2");
            if (attribute2 != null) pasiveValue = Convert.ToSingle(attribute2.Value);

            XElement attribute4 = passiveSkill.Element("effect" + effectNumber + "_reserved4");
            if (attribute4 != null) procentValue = Convert.ToSingle(attribute4.Value);

            XElement lvl = passiveSkill.Element("effect" + effectNumber + "_basiclv");
            if (lvl != null) skillLevel = Convert.ToByte(lvl.Value);
        }
        
        #endregion

    }
}



                